-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
89f5f5c
commit b984913
Showing
3 changed files
with
263 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,131 @@ | ||
<?php /** | ||
* @category Fuko | ||
* @package Fuko\Source | ||
* | ||
* @author Kaloyan Tsvetkov (KT) <kaloyan@kaloyan.info> | ||
* @link https://github.com/fuko-php/source/ | ||
* @license https://opensource.org/licenses/MIT | ||
*/ | ||
|
||
namespace Fuko\Source; | ||
|
||
use InvalidArgumentException; | ||
use RuntimeException; | ||
|
||
use function ceil; | ||
use function file_exists; | ||
use function fclose; | ||
use function fgets; | ||
use function fopen; | ||
|
||
/** | ||
* Source Code Reader | ||
* | ||
* Use this class to extract source code lines using a code reference (filename + line) | ||
* | ||
* @package Fuko\Source | ||
*/ | ||
class Code | ||
{ | ||
/** | ||
* @var integer default LOCs (lines of code) returned | ||
* @see \Fuko\Source\Code::getLinesAt() | ||
*/ | ||
const LOC_DEFAULT = 7; | ||
|
||
/** | ||
* @var integer max numer of LOCs (lines of code) returned | ||
* @see \Fuko\Source\Code::getLinesAt() | ||
*/ | ||
const LOC_MAX = 20; | ||
|
||
/** | ||
* @var string source filename | ||
*/ | ||
protected $sourceFilename = ''; | ||
|
||
/** | ||
* Source Code Constructor | ||
* | ||
* @param string $filename | ||
*/ | ||
function __construct(string $filename) | ||
{ | ||
$this->sourceFilename = $filename; | ||
|
||
} | ||
|
||
/** | ||
* Get Source Code Lines | ||
* | ||
* @param integer $line target line of the reference | ||
* @param integer $locs how many LOCs (lines of code) to return | ||
* @return array | ||
* @throws InvalidArgumentException | ||
* @throws RuntimeException | ||
*/ | ||
function getLinesAt(int $line, int $locs = null) : array | ||
{ | ||
if (!file_exists($this->sourceFilename)) | ||
{ | ||
throw new RuntimeException( | ||
"Source code file not found: {$this->sourceFilename}", | ||
20004 | ||
); | ||
} | ||
|
||
if ($line < 1) | ||
{ | ||
throw new InvalidArgumentException( | ||
"The \$line argument must be a positive integer, instead {$line} given", | ||
20005 | ||
); | ||
} | ||
|
||
if (null !== $locs) | ||
{ | ||
if ($locs < 1) | ||
{ | ||
throw new InvalidArgumentException( | ||
"The \$locs argument must be a positive integer, instead {$locs} given", | ||
20006 | ||
); | ||
} | ||
} | ||
|
||
// by default show 7 lines, but do not go beyond 20 | ||
// | ||
$locs = $locs ?? static::LOC_DEFAULT; | ||
if (static::LOC_MAX < $locs) | ||
{ | ||
$locs = static::LOC_MAX; | ||
} | ||
|
||
$before = ceil(($locs-1)/2); | ||
$after = $locs -1 - $before; | ||
|
||
$from = ($from = $line - $before) > 1 ? $from : 1; | ||
$to = $line + $after; | ||
|
||
$lines = array(); | ||
$fp = fopen($this->sourceFilename, 'r'); | ||
|
||
$atLine = 0; | ||
while (false !== ($lineCode = fgets($fp))) | ||
{ | ||
if (++$atLine < $from) | ||
{ | ||
continue; | ||
} | ||
if ($atLine > $to) | ||
{ | ||
break; | ||
} | ||
|
||
$lines[ $atLine ] = $lineCode; | ||
} | ||
fclose($fp); | ||
|
||
return $lines; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
<?php | ||
|
||
namespace Fuko\Source\Tests; | ||
|
||
use Fuko\Source\Code; | ||
use PHPUnit\Framework\TestCase; | ||
|
||
use function file; | ||
|
||
class CodeTest extends TestCase | ||
{ | ||
/** | ||
* @covers Fuko\Source\Code::getLinesAt() | ||
* @expectedException RuntimeException | ||
*/ | ||
function testMissingFile() | ||
{ | ||
$source = new Code('/i/am/not/here'); | ||
$source->getLinesAt(123); | ||
} | ||
|
||
/** | ||
* @covers Fuko\Source\Code::getLinesAt() | ||
* @expectedException InvalidArgumentException | ||
*/ | ||
function testNegativeSourceLine() | ||
{ | ||
$source = new Code(__FILE__); | ||
$source->getLinesAt(-2); | ||
} | ||
|
||
/** | ||
* @covers Fuko\Source\Code::getLinesAt() | ||
* @expectedException InvalidArgumentException | ||
*/ | ||
function testZeroSourceLine() | ||
{ | ||
$source = new Code(__FILE__); | ||
$source->getLinesAt(0); | ||
} | ||
|
||
/** | ||
* @covers Fuko\Source\Code::getLinesAt() | ||
* @expectedException InvalidArgumentException | ||
*/ | ||
function testNegativeLOCs() | ||
{ | ||
$source = new Code(__FILE__); | ||
$source->getLinesAt(2, -2); | ||
} | ||
|
||
/** | ||
* @covers Fuko\Source\Code::getLinesAt() | ||
* @expectedException InvalidArgumentException | ||
*/ | ||
function testZeroLOCs() | ||
{ | ||
$source = new Code(__FILE__); | ||
$source->getLinesAt(1, 0); | ||
} | ||
|
||
/** | ||
* @covers Fuko\Source\Code::getLinesAt() | ||
*/ | ||
function testGetLinesAt() | ||
{ | ||
$source = new Code($composer = __DIR__ . '/../composer.json'); | ||
$lines = file($composer); | ||
|
||
$this->assertEquals( | ||
$source->getLinesAt(1, 1), | ||
[ 1 => $lines[0] ] | ||
); | ||
|
||
$this->assertEquals( | ||
$source->getLinesAt(4), [ | ||
1 => $lines[0], | ||
2 => $lines[1], | ||
3 => $lines[2], | ||
4 => $lines[3], | ||
5 => $lines[4], | ||
6 => $lines[5], | ||
7 => $lines[6], | ||
]); | ||
|
||
$this->assertEquals( | ||
$source->getLinesAt(4, 3), [ | ||
3 => $lines[2], | ||
4 => $lines[3], | ||
5 => $lines[4], | ||
]); | ||
} | ||
} |