From a6105b992b8ca19df77bd12ef29e19538c44dfca Mon Sep 17 00:00:00 2001 From: Rodolfo Berrios <20590102+rodber@users.noreply.github.com> Date: Mon, 8 Jan 2024 16:50:08 -0300 Subject: [PATCH] typos --- .github/banner/writer-logo.svg | 39 +++++++++++++ .github/banner/writer-social.png | Bin 0 -> 30369 bytes README.md | 91 ++++++++++++++++++++++++++++++- composer.json | 2 +- src/StreamWriter.php | 5 +- src/WritersInstance.php | 8 ++- src/functions.php | 40 +++++--------- tests/FunctionsTest.php | 53 ++++++++++++++++++ tests/WritersInstanceTest.php | 1 + 9 files changed, 205 insertions(+), 34 deletions(-) create mode 100644 .github/banner/writer-logo.svg create mode 100644 .github/banner/writer-social.png create mode 100644 tests/FunctionsTest.php diff --git a/.github/banner/writer-logo.svg b/.github/banner/writer-logo.svg new file mode 100644 index 0000000..1ea0a8a --- /dev/null +++ b/.github/banner/writer-logo.svg @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.github/banner/writer-social.png b/.github/banner/writer-social.png new file mode 100644 index 0000000000000000000000000000000000000000..96872baf53e9ada70b5ec9cf1f8c7fab55d7accb GIT binary patch literal 30369 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 literal 0 HcmV?d00001 diff --git a/README.md b/README.md index 33db249..5f399b6 100644 --- a/README.md +++ b/README.md @@ -18,13 +18,100 @@ [![Technical Debt](https://sonarcloud.io/api/project_badges/measure?project=chevere_writer&metric=sqale_index)](https://sonarcloud.io/dashboard?id=chevere_writer) [![CodeFactor](https://www.codefactor.io/repository/github/chevere/writer/badge)](https://www.codefactor.io/repository/github/chevere/writer) +![Writer](.github/banner/writer-logo.svg) + +## Summary + +Writer provides tooling for writing to streams. + +## Installing + +Writer is available through [Packagist](https://packagist.org/packages/chevere/writer) and the repository source is at [chevere/writer](https://github.com/chevere/writer). + +```sh +composer require chevere/writer +``` + +## StreamWriter + +Use `StreamWriter` to write strings to a stream. + +```php +use Chevere\Writer\StreamWriter; +use function Chevere\Writer\streamFor; + +$stream = streamFor('php://output', 'r'); +$writer = new StreamWriter($stream); +$writer->write('Hello, world!'); +``` + +## NullWriter + +Use `NullWriter` when requiring `null` write override. + +## Writers + +Use `Writers` to interact with pre-defined streams for output, error, debug and log. By default only output and error streams are defined. + +| Stream | Default | +| ------ | ------------ | +| output | StreamWriter | +| error | StreamWriter | +| debug | NullWriter | +| log | NullWriter | + +```php +use Chevere\Writer\Writers; + +$writers = new Writers(); +$writers->error(); +$writers->debug(); +$writers->log(); +``` + +### Output stream + +Use `output` to interact with the output stream. Use `withOutput` to set a custom output stream. + +```php +$with = $writers->withOutput($stream); +$with->output(); // $stream +``` + +### Error stream + +Use `error` to interact with the error stream. Use `withError` to set a custom error stream. + +```php +$with = $writers->withError($stream); +$with->error(); // $stream +``` + +### Debug stream + +Use `debug` to interact with the debug stream. Use `withDebug` to set a custom debug stream. + +```php +$with = $writers->withDebug($stream); +$with->debug(); // $stream +``` + +### Log stream + +Use `log` to interact with the log stream. Use `withLog` to set a custom log stream. + +```php +$with = $writers->withLog($stream); +$with->log(); // $stream +``` + ## Documentation -Documentation is available at [chevere.org](https://chevere.org/). +Documentation is available at [chevere.org](https://chevere.org/packages/writer). ## License -Copyright 2023 [Rodolfo Berrios A.](https://rodolfoberrios.com/) +Copyright [Rodolfo Berrios A.](https://rodolfoberrios.com/) Chevere is licensed under the Apache License, Version 2.0. See [LICENSE](LICENSE) for the full license text. diff --git a/composer.json b/composer.json index ab2ac20..76f1be7 100644 --- a/composer.json +++ b/composer.json @@ -1,6 +1,6 @@ { "name": "chevere/writer", - "description": "A chevere writer package", + "description": "Tooling for writing to streams", "homepage": "https://chevere.org", "type": "library", "license": "Apache-2.0", diff --git a/src/StreamWriter.php b/src/StreamWriter.php index 39f96b0..ac3cb26 100644 --- a/src/StreamWriter.php +++ b/src/StreamWriter.php @@ -18,7 +18,6 @@ use Psr\Http\Message\StreamInterface; use RuntimeException; use Throwable; -use function Chevere\Message\message; /** * @codeCoverageIgnore @@ -31,7 +30,7 @@ public function __construct( ) { if (! $this->stream->isWritable()) { throw new InvalidArgumentException( - (string) message('Stream provided is not writable') + 'Stream provided is not writable' ); } } @@ -48,7 +47,7 @@ public function write(string $string): void } catch (Throwable $e) { throw new RuntimeException( previous: $e, - message: (string) message('Unable to write provided string') + message: 'Unable to write provided string' ); } } diff --git a/src/WritersInstance.php b/src/WritersInstance.php index b35fd9d..846d516 100644 --- a/src/WritersInstance.php +++ b/src/WritersInstance.php @@ -15,7 +15,6 @@ use Chevere\Writer\Interfaces\WritersInterface; use LogicException; -use function Chevere\Message\message; final class WritersInstance { @@ -26,11 +25,16 @@ public function __construct(WritersInterface $writers) self::$instance = $writers; } + public function __destruct() + { + self::$instance = null; + } + public static function get(): WritersInterface { if (! isset(self::$instance)) { throw new LogicException( - (string) message('No writers instance present') + 'No writers instance present' ); } diff --git a/src/functions.php b/src/functions.php index 4ae724e..8f57ae9 100644 --- a/src/functions.php +++ b/src/functions.php @@ -14,52 +14,40 @@ namespace Chevere\Writer; use Chevere\Writer\Interfaces\WritersInterface; +use ErrorException; use InvalidArgumentException; use Nyholm\Psr7\Stream; use Psr\Http\Message\StreamInterface; -use Throwable; -use function Chevere\Message\message; -use function Safe\fopen; -/** - * @codeCoverageIgnore - */ function writers(): WritersInterface { return WritersInstance::get(); } /** - * @codeCoverageIgnore - * * @throws InvalidArgumentException */ function streamFor(string $uri, string $mode): StreamInterface { - try { - return Stream::create(fopen($uri, $mode)); - } catch (Throwable $e) { - throw new InvalidArgumentException( - previous: $e, - message: (string) message( - 'Unable to create stream for `%uri%`', - uri: $uri - ) + error_clear_last(); + $fopen = @fopen($uri, $mode); + if ($fopen === false) { + $error = error_get_last(); + + throw new ErrorException( + message: $error['message'] ?? 'An error occured', + code: 0, + severity: $error['type'] ?? 1 ); } + + return Stream::create($fopen); } /** - * @codeCoverageIgnore + * @throws InvalidArgumentException */ function streamTemp(string $content = ''): StreamInterface { - try { - return Stream::create($content); - } catch (Throwable $e) { - throw new InvalidArgumentException( - previous: $e, - message: (string) message('Unable to create temp stream') - ); - } + return Stream::create($content); } diff --git a/tests/FunctionsTest.php b/tests/FunctionsTest.php new file mode 100644 index 0000000..682fafe --- /dev/null +++ b/tests/FunctionsTest.php @@ -0,0 +1,53 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Chevere\Tests; + +use Chevere\Writer\Writers; +use Chevere\Writer\WritersInstance; +use ErrorException; +use PHPUnit\Framework\TestCase; +use function Chevere\Writer\streamFor; +use function Chevere\Writer\writers; + +final class FunctionsTest extends TestCase +{ + public function testWritersInstance(): void + { + $writers = new Writers(); + $instance = new WritersInstance($writers); + $this->assertSame($instance->get(), writers()); + unset($instance); + } + + public function testStreamFor(): void + { + $this->expectNotToPerformAssertions(); + $uri = 'php://output'; + $mode = 'r+'; + streamFor($uri, $mode); + } + + public function testStreamForError(): void + { + $uri = '404'; + $mode = 'r+'; + $this->expectException(ErrorException::class); + $this->expectExceptionMessage( + <<assertSame($writers, $instance::get()); + unset($instance); } }