-
Notifications
You must be signed in to change notification settings - Fork 35
Commit
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,159 @@ | ||
<?php declare(strict_types=1); | ||
|
||
namespace Yay; | ||
|
||
use function yay_parse; | ||
|
||
use | ||
SplFileObject, | ||
SplFileInfo | ||
; | ||
|
||
final class StreamWrapper { | ||
const | ||
SCHEME = 'yay' | ||
; | ||
|
||
protected static | ||
$registered = false | ||
; | ||
|
||
protected | ||
/** | ||
* @type SplFileInfo | ||
*/ | ||
$fileMeta, | ||
/** | ||
* @type SplFileObject | ||
*/ | ||
$file | ||
; | ||
|
||
static function register() | ||
{ | ||
if (true === self::$registered) return; | ||
|
||
if (@stream_wrapper_register(self::SCHEME, __CLASS__) === false) | ||
throw new YayException( | ||
'A handler has already been registered for the ' . | ||
self::SCHEME . ' protocol.' | ||
); | ||
|
||
self::$registered = true; | ||
} | ||
|
||
static function unregister() | ||
{ | ||
if (!self::$registered) { | ||
if (in_array(self::SCHEME, stream_get_wrappers())) | ||
throw new YayException( | ||
'The URL wrapper for the protocol ' . self::SCHEME . | ||
' was not registered with this version of YAY.' | ||
); | ||
|
||
return; | ||
} | ||
|
||
if (!@stream_wrapper_unregister(self::SCHEME)) | ||
throw new YayException( | ||
'Failed to unregister the URL wrapper for the ' . self::SCHEME . | ||
' protocol.' | ||
); | ||
|
||
self::$registered = false; | ||
} | ||
|
||
function stream_open(string $path, string $mode, int $flags, &$opened_path) : bool | ||
{ | ||
$path = preg_replace('#^' . self::SCHEME . '://#', '', $path); | ||
|
||
if (STREAM_USE_PATH & $flags && $path[0] !== '/') | ||
$path = dirname(debug_backtrace()[0]['file']) . '/' . $path; | ||
This comment has been minimized.
Sorry, something went wrong. |
||
|
||
$this->fileMeta = new SplFileInfo($path); | ||
|
||
$opened_path = $path; | ||
|
||
if (! $this->fileMeta->isReadable()) return false; | ||
|
||
$this->file = $this->fileMeta->openFile($mode); | ||
|
||
return true; | ||
} | ||
|
||
function stream_close(){} | ||
|
||
function stream_read($lengh) : string { | ||
return | ||
! $this->file->eof() | ||
? yay_parse($this->file->fread($lengh), $this->file->getPath()) | ||
: '' | ||
; | ||
} | ||
|
||
function stream_eof() : bool { return $this->file->eof(); } | ||
|
||
function stream_stat() : array | ||
{ | ||
$stat = | ||
$this->file ? [ | ||
'dev' => 0, | ||
'ino' => 0, | ||
'mode' => 'rb', | ||
// 'mode' => $this->file->getMode(), | ||
'nlink' => 0, | ||
'uid' => $this->file->getOwner(), | ||
'gid' => $this->file->getGroup(), | ||
'rdev' => 0, | ||
'size' => $this->file->getSize(), | ||
'atime' => $this->file->getATime(), | ||
'mtime' => $this->file->getMTime(), | ||
'ctime' => $this->file->getCTime(), | ||
'blksize' => -1, | ||
'blocks' => -1 | ||
] : [] | ||
; | ||
|
||
return array_merge(array_values($stat), $stat); | ||
} | ||
|
||
function url_stat() { $this->notImplemented(__FUNCTION__); } | ||
|
||
function stream_write() { $this->notImplemented(__FUNCTION__); } | ||
|
||
function stream_truncate() { $this->notImplemented(__FUNCTION__); } | ||
|
||
function stream_metadata() { $this->notImplemented(__FUNCTION__); } | ||
|
||
function stream_tell() { $this->notImplemented(__FUNCTION__); } | ||
|
||
function stream_seek() { $this->notImplemented(__FUNCTION__); } | ||
|
||
function stream_flush() { $this->notImplemented(__FUNCTION__); } | ||
|
||
function stream_cast() { $this->notImplemented(__FUNCTION__); } | ||
|
||
function stream_lock() { $this->notImplemented(__FUNCTION__); } | ||
|
||
function stream_set_option() { $this->notImplemented(__FUNCTION__); } | ||
|
||
function unlink() { $this->notImplemented(__FUNCTION__); } | ||
|
||
function rename() { $this->notImplemented(__FUNCTION__); } | ||
|
||
function mkdir() { $this->notImplemented(__FUNCTION__); } | ||
|
||
function rmdir() { $this->notImplemented(__FUNCTION__); } | ||
|
||
function dir_opendir() { $this->notImplemented(__FUNCTION__); } | ||
|
||
function dir_readdir() { $this->notImplemented(__FUNCTION__); } | ||
|
||
function dir_rewinddir() { $this->notImplemented(__FUNCTION__); } | ||
|
||
function dir_closedir() { $this->notImplemented(__FUNCTION__); } | ||
|
||
private function notImplemented(string $from) { | ||
throw new YayException(__CLASS__ . "->{$from} is not implemented."); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
<?php declare(strict_types=1); | ||
|
||
namespace Yay; | ||
|
||
/** | ||
* @group large | ||
*/ | ||
class StreamWrapperTest extends \PHPUnit_Framework_TestCase { | ||
|
||
const | ||
FIXTURES_DIR = 'fixtures', | ||
ABSOLUTE_FIXTURES_DIR = __DIR__ . '/' . self::FIXTURES_DIR | ||
; | ||
|
||
static function setupBeforeClass() { StreamWrapper::register(); } | ||
|
||
function syntaxErrorProvider() { | ||
|
||
$fixtures = [ | ||
['/syntax_error.php', "syntax error, unexpected '}'"], | ||
['/preprocessor_error.php', "Undefined token type 'T_HAKUNAMATATA'"] | ||
]; | ||
|
||
foreach ($fixtures as list($file, $message)) { | ||
yield [self::FIXTURES_DIR . $file, $message]; | ||
yield [self::ABSOLUTE_FIXTURES_DIR . $file, $message]; | ||
} | ||
} | ||
|
||
/** | ||
* @dataProvider syntaxErrorProvider | ||
*/ | ||
function testStreamWrapperOnSyntaxError(string $file, string $error) { | ||
$this->setExpectedException(\ParseError::class, $error); | ||
include 'yay://' . $file; | ||
} | ||
|
||
function fixtureProvider() { | ||
$fixtures = [ | ||
'/type_alias.php' | ||
]; | ||
|
||
foreach ($fixtures as $file) { | ||
yield [self::FIXTURES_DIR . $file]; | ||
yield [self::ABSOLUTE_FIXTURES_DIR . $file]; | ||
} | ||
} | ||
|
||
/** | ||
* @dataProvider fixtureProvider | ||
* @runInSeparateProcess | ||
*/ | ||
function testStreamWrapperInclusion(string $file) { | ||
include 'yay://' . $file; | ||
$result = \Yay\Fixtures\test_type_alias(__FILE__); | ||
$this->assertEquals('pass', $result); | ||
} | ||
|
||
static function tearDownAfterClass() { StreamWrapper::unregister(); } | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
<?php | ||
|
||
macro { T_HAKUNAMATATA·foo } >> { }; | ||
This comment has been minimized.
Sorry, something went wrong.
This comment has been minimized.
Sorry, something went wrong.
This comment has been minimized.
Sorry, something went wrong.
marcioAlmada
Author
Owner
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
<?php { blah } |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
<?php namespace Yay\Fixtures; | ||
|
||
macro { | ||
type T_STRING·newtype = T_STRING·basetype; | ||
} >> { | ||
macro { | ||
\\(·either(instanceof, ·token(','), ·token('('), ·token(':'))·prec) T_STRING·newtype | ||
} >> { | ||
\\(·prec) T_STRING·basetype | ||
} | ||
} | ||
|
||
type Path = string; | ||
|
||
function test_type_alias(Path $p) : Path { | ||
return 'pass'; | ||
} |
debug_backtrace()
😭