Completed
Push — develop ( 5f7df1...9cb564 )
by Matteo
10s
created

DiffChunk::next()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1
Metric Value
dl 0
loc 4
ccs 3
cts 3
cp 1
rs 10
cc 1
eloc 2
nc 1
nop 0
crap 1
1
<?php
2
/**
3
 * GitElephant - An abstraction layer for git written in PHP
4
 * Copyright (C) 2013  Matteo Giachino
5
 *
6
 * This program is free software: you can redistribute it and/or modify
7
 * it under the terms of the GNU General Public License as published by
8
 * the Free Software Foundation, either version 3 of the License, or
9
 * (at your option) any later version.
10
 *
11
 * This program is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU General Public License
17
 * along with this program.  If not, see [http://www.gnu.org/licenses/].
18
 */
19
20
namespace GitElephant\Objects\Diff;
21
22
/**
23
 * A single portion of a file changed in a diff
24
 *
25
 * @author Matteo Giachino <[email protected]>
26
 */
27
class DiffChunk implements \ArrayAccess, \Countable, \Iterator
28
{
29
    /**
30
     * the cursor position
31
     *
32
     * @var int
33
     */
34
    private $position;
35
36
    /**
37
     * diff start line from original file
38
     *
39
     * @var int
40
     */
41
    private $originStartLine;
42
43
    /**
44
     * diff end line from original file
45
     *
46
     * @var int
47
     */
48
    private $originEndLine;
49
50
    /**
51
     * diff start line from destination file
52
     *
53
     * @var int
54
     */
55
    private $destStartLine;
56
57
    /**
58
     * diff end line from destination file
59
     *
60
     * @var int
61
     */
62
    private $destEndLine;
63
64
    /**
65
     * hunk header line
66
     *
67
     * @var string
68
     */
69
    private $headerLine;
70
71
    /**
72
     * array of lines
73
     *
74
     * @var array
75
     */
76
    private $lines;
77
78
    /**
79
     * Class constructor
80
     *
81
     * @param array $lines output lines from git binary
82
     *
83
     * @throws \Exception
84
     */
85 2
    public function __construct($lines)
86
    {
87 2
        $this->position = 0;
88
89 2
        $this->getLinesNumbers($lines[0]);
90 2
        $this->parseLines(array_slice($lines, 1));
91 2
    }
92
93
    /**
94
     * Parse lines
95
     *
96
     * @param array $lines output lines
97
     *
98
     * @throws \Exception
99
     */
100 2
    private function parseLines($lines)
101
    {
102 2
        $originUnchanged = $this->originStartLine;
103 2
        $destUnchanged = $this->destStartLine;
104
105 2
        $deleted = $this->originStartLine;
106 2
        $new = $this->destStartLine;
107 2
        foreach ($lines as $line) {
108 2
            if (preg_match('/^\+(.*)/', $line)) {
109 2
                $this->lines[] = new DiffChunkLineAdded($new++, preg_replace('/\+(.*)/', ' $1', $line));
110 2
                $destUnchanged++;
111 2
            } else {
112 2
                if (preg_match('/^-(.*)/', $line)) {
113 1
                    $this->lines[] = new DiffChunkLineDeleted($deleted++, preg_replace('/-(.*)/', ' $1', $line));
114 1
                    $originUnchanged++;
115 1
                } else {
116 2
                    if (preg_match('/^ (.*)/', $line) || $line == '') {
117 2
                        $this->lines[] = new DiffChunkLineUnchanged($originUnchanged++, $destUnchanged++, $line);
118 2
                        $deleted++;
119 2
                        $new++;
120 2
                    } else {
121 2
                        if (!preg_match('/\\ No newline at end of file/', $line)) {
122
                            throw new \Exception(sprintf('GitElephant was unable to parse the line %s', $line));
123
                        }
124
                    }
125
                }
126
            }
127 2
        }
128 2
    }
129
130
    /**
131
     * Get line numbers
132
     *
133
     * @param string $line a single line
134
     */
135 2
    private function getLinesNumbers($line)
136
    {
137 2
        $matches = array();
138 2
        preg_match('/@@ -(.*) \+(.*) @@?(.*)/', $line, $matches);
139 2
        if (!strpos($matches[1], ',')) {
140
            // one line
141
            $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...
142
            $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...
143
        } else {
144 2
            list($this->originStartLine, $this->originEndLine) = explode(',', $matches[1]);
145
        }
146 2
        if (!strpos($matches[2], ',')) {
147
            // one line
148 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...
149 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...
150 1
        } else {
151 1
            list($this->destStartLine, $this->destEndLine) = explode(',', $matches[2]);
152
        }
153 2
    }
154
155
    /**
156
     * destStartLine getter
157
     *
158
     * @return int
159
     */
160
    public function getDestStartLine()
161
    {
162
        return $this->destStartLine;
163
    }
164
165
    /**
166
     * destEndLine getter
167
     *
168
     * @return int
169
     */
170
    public function getDestEndLine()
171
    {
172
        return $this->destEndLine;
173
    }
174
175
    /**
176
     * originStartLine getter
177
     *
178
     * @return int
179
     */
180
    public function getOriginStartLine()
181
    {
182
        return $this->originStartLine;
183
    }
184
185
    /**
186
     * originEndLine getter
187
     *
188
     * @return int
189
     */
190
    public function getOriginEndLine()
191
    {
192
        return $this->originEndLine;
193
    }
194
195
    /**
196
    * Get hunk header line
197
    *
198
    * @return string
199
    */
200
    public function getHeaderLine()
201
    {
202
        if (null === $this->headerLine) {
203
            $line  = '@@';
204
            $line .= ' -' . $this->getOriginStartLine() . ',' . $this->getOriginEndLine();
205
            $line .= ' +' . $this->getDestStartLine() . ',' . $this->getDestEndLine();
206
            $line .= ' @@';
207
208
            $this->headerLine = $line;
209
        }
210
211
        return $this->headerLine;
212
    }
213
214
    /**
215
     * Get Lines
216
     *
217
     * @return array
218
     */
219
    public function getLines()
220
    {
221
        return $this->lines;
222
    }
223
224
    /**
225
     * ArrayAccess interface
226
     *
227
     * @param int $offset offset
228
     *
229
     * @return bool
230
     */
231
    public function offsetExists($offset)
232
    {
233
        return isset($this->lines[$offset]);
234
    }
235
236
    /**
237
     * ArrayAccess interface
238
     *
239
     * @param int $offset offset
240
     *
241
     * @return null
242
     */
243
    public function offsetGet($offset)
244
    {
245
        return isset($this->lines[$offset]) ? $this->lines[$offset] : null;
246
    }
247
248
    /**
249
     * ArrayAccess interface
250
     *
251
     * @param int   $offset offset
252
     * @param mixed $value  value
253
     */
254
    public function offsetSet($offset, $value)
255
    {
256
        if (is_null($offset)) {
257
            $this->lines[] = $value;
258
        } else {
259
            $this->lines[$offset] = $value;
260
        }
261
    }
262
263
    /**
264
     * ArrayAccess interface
265
     *
266
     * @param int $offset offset
267
     */
268
    public function offsetUnset($offset)
269
    {
270
        unset($this->lines[$offset]);
271
    }
272
273
    /**
274
     * Countable interface
275
     *
276
     * @return int|void
277
     */
278 1
    public function count()
279
    {
280 1
        return count($this->lines);
281
    }
282
283
    /**
284
     * Iterator interface
285
     *
286
     * @return mixed
287
     */
288 1
    public function current()
289
    {
290 1
        return $this->lines[$this->position];
291
    }
292
293
    /**
294
     * Iterator interface
295
     */
296 1
    public function next()
297
    {
298 1
        ++$this->position;
299 1
    }
300
301
    /**
302
     * Iterator interface
303
     *
304
     * @return int
305
     */
306
    public function key()
307
    {
308
        return $this->position;
309
    }
310
311
    /**
312
     * Iterator interface
313
     *
314
     * @return bool
315
     */
316 1
    public function valid()
317
    {
318 1
        return isset($this->lines[$this->position]);
319
    }
320
321
    /**
322
     * Iterator interface
323
     */
324 1
    public function rewind()
325
    {
326 1
        $this->position = 0;
327 1
    }
328
}
329